//! @Author: DengLibin
//! @Date: Create in 2023-11-06 17:25:05
//! @Description: hello world

use std::{collections::HashMap, path::Path};
use askama::Template;
use axum::{
    body::Body,
    extract::{Multipart, Query},
    http::Request,
    response::{Html, IntoResponse},
    routing::{get, post},
    Form, Json, Router,
};

use hyper::StatusCode;
use log::{error, info, warn};

use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use tokio::{
    fs::{self, File},
    io::AsyncWriteExt,
};

use crate::{
    sys::global::{to_global_result, GlobalResult},
    web::Resdata,
};
use crate::web::controller::template_obj::HelloTemplate;

#[derive(Debug, Serialize, Deserialize)]

pub struct User {
    pub id: u64,
    pub name: String,
}

/// @Author: DengLibin
/// @Date: Create in 2024-07-17 14:21:45
/// @Description: 路由
pub async fn route(router: Router) -> Router {
    //路由
    let mut router = router.route("/", get(hello_world));
    router = router.route("/test_log", get(test_log));

    //请求体
    router = router.route("/string_body", post(string_body));
    router = router.route("/request", post(request));
    //get查询参数
    router = router.route("/query", get(query));
    //接收json数组
    router = router.route("/json_arr", post(json_arr));
    //接送json对象
    router = router.route("/json_obj", post(json_obj));
    //接收表单提交
    router = router.route("/form_obj", post(form_obj));
    //上传文件
    router = router.route("/upload", post(upload));
    //响应json
    router = router.route("/json", get(json));
    //重定向
    router = router.route("/redirect", get(redirect));
    //下载文件
    router = router.route("/down", get(down));
    //返回html
    router = router.route("/html", get(html));
    router
}

/// @Author: DengLibin
/// @Date: Create in 2023-11-06 17:26:27
/// @Description: hello world
pub async fn hello_world() -> Html<&'static str> {
    info!("get hello world");
    Html("<h1>Hello, World!</h1>")
}

/// @Author: DengLibin
/// @Date: Create in 2023-11-06 18:08:10
/// @Description: json
pub async fn json() -> Json<Value> {
    Json(json!(User {
        id: 234_u64,
        name: "张三".into()
    }))
}

/// @Author: DengLibin
/// @Date: Create in 2023-11-07 16:13:31
/// @Description: 获取查询参数
pub async fn query(Query(params): Query<HashMap<String, String>>) -> Json<Value> {
    for ele in params.iter() {
        println!("{}-{}", ele.0, ele.1);
    }
    Json(json!(params))
}
/// @Author: DengLibin
/// @Date: Create in 2023-11-07 16:30:24
/// @Description: 获取请求体
pub async fn string_body(body: String) -> Json<Value> {
    Json(json!(body))
}

/// @Author: DengLibin
/// @Date: Create in 2023-11-07 16:30:40
/// @Description:
pub async fn request(request: Request<Body>) -> Json<Value> {
    let r = request.uri();
    Json(json!(r.path()))
}

/// @Author: DengLibin
/// @Date: Create in 2023-11-07 16:35:27
/// @Description: 接收json
pub async fn json_obj(Json(user): Json<User>) -> Json<User> {
    Json(user)
}

/// @Author: DengLibin
/// @Date: Create in 2023-11-07 16:35:27
/// @Description: 接收json
pub async fn json_arr(Json(users): Json<Vec<User>>) -> Json<Vec<User>> {
    Json(users)
}

/// @Author: DengLibin
/// @Date: Create in 2023-11-07 16:35:27
/// @Description: 接收 form
pub async fn form_obj(Form(user): Form<User>) -> Json<User> {
    Json(user)
}

/// @Author: DengLibin
/// @Date: Create in 2024-06-28 15:23:33
/// @Description:
pub async fn test_log() -> Html<&'static str> {
    info!(target: "info_logger", "this is info log");
    warn!(target: "warn_logger", "this is warn log");
    log::error!(target: "error_logger", "this is error log");

    Html("<h1>Ok Log</h1>")
}

/// @Author: DengLibin
/// @Date: Create in 2024-07-23 17:38:08
/// @Description: 重定向
pub async fn redirect() -> impl axum::response::IntoResponse {
    axum::response::Redirect::temporary("/static/index.html")
}

/// @Author: DengLibin
/// @Date: Create in 2024-07-23 18:46:03
/// @Description: 文件下载
pub async fn down(
    Query(params): Query<HashMap<String, String>>,
) -> impl axum::response::IntoResponse {
    let r = check_file_param(&params).await;
    let (file_f, file_name, file_size) = match r {
        Ok(file_msg) => (file_msg.0, file_msg.1, file_msg.2),
        Err(err) => {
            error!("获取文件参数异常:{}", err);
            return StatusCode::NOT_FOUND.into_response();
        }
    };

    super::download_file(&file_f, &file_name, file_size).await
}


///@author Denglibin
///@date 2025/3/24 17:34
///@desc 使用模板引擎返回html
pub async fn html() -> Html<String> {
    let hello  = HelloTemplate { name: "world" }; // instantiate your struct
    let html = hello.render();
    if let Ok(h) = html {
        Html(h)
    }else {
        log::error!("模板渲染异常:{}", html.unwrap_err());
        Html("".into())
    }

}

/// @Author: DengLibin
/// @Date: Create in 2023-11-07 18:50:04
/// @Description: 上传文件
pub async fn upload(multipart: Multipart) -> Json<Resdata<()>> {
    let r: GlobalResult<()> = save_file(multipart).await;

    Json(Resdata::ok_result(r))
}

/// @Author: DengLibin
/// @Date: Create in 2024-07-23 19:04:05
/// @Description: 保存文件
async fn save_file(mut multipart: Multipart) -> GlobalResult<()> {
    let save_dir = "./upload";
    // 检查路径是否存在
    if !fs::metadata(save_dir).await.is_ok() {
        // 如果路径不存在，则创建目录
        to_global_result(fs::create_dir_all(save_dir).await)?;
    }
    loop {
        let r = multipart.next_field().await;
        let o = to_global_result(r)?;
        if let Some(mut field) = o {
            let field_name_o = field.name();
            if let Some(field_name) = field_name_o {
                if field_name == "file" {
                    //文件字段名
                    let x = field.file_name();
                    if let Some(n) = x {
                        let filename = n.to_string();
                        let mut file = to_global_result(
                            File::create(format!("{}/{}", save_dir, filename)).await,
                        )?;

                        // 逐块读取文件内容并写入文件
                        while let Some(chunk) = field.chunk().await.unwrap() {
                            to_global_result(file.write_all(&chunk).await)?;
                        }
                    }
                }
            }
        } else {
            break;
        }
    }
    Ok(())
}

///检查文件参数，返回文件路径,文件名,大小
async fn check_file_param(
    params: &HashMap<String, String>,
) -> GlobalResult<(String, String, usize)> {
    // 文件路径参数
    let file_path = params.get("file_path");
    //文件路径
    let file_f = if let Some(path) = file_path {
        path
    } else {
        // return Err(GlobalError::new("文件路径参数file_path不能为空".into()));
        return Err(anyhow::anyhow!("文件路径参数file_path不能为空".to_string()));
    };
    //元数据
    let meta_r = tokio::fs::metadata(file_f).await;
    // 获取文件大小
    let file_size = match meta_r {
        Ok(meta) => meta.len() as usize,
        Err(err) => {
            // return Err(GlobalError::new(err.to_string()));
            return Err(anyhow::anyhow!(err.to_string()));
        }
    };
    //获取文件名
    let file_name_o = Path::new(file_f).file_name();
    let file_name = if let Some(name) = file_name_o {
        let name_o = name.to_str();
        if let Some(name) = name_o {
            name
        } else {
            // return Err(GlobalError::new("获取文件名失败".into()));
            return Err(anyhow::anyhow!("获取文件名失败".to_string()));
        }
    } else {
        // return Err(GlobalError::new("获取文件名失败".into()));
        return Err(anyhow::anyhow!("获取文件名失败".to_string()));
    };

    Ok((file_f.into(), file_name.into(), file_size))
}
